<template>
  <div
    class="scroll-container"
    ref="scrollContainer"
    @wheel.prevent="handleScroll"
    @mouseover="hoverPane($event)"
    @mouseleave="leavePane($event)"
  >
    <span
      class="scrollBar scrollBar-left"
      v-show="state.scrollVisible"
      @click="scrollLeft"
      :style="{
        //'border-right': '1px solid ' + theme.color,
        color: '#fff',
      }"
    >
      <el-icon style=""><ArrowLeft /></el-icon>
    </span>

    <div class="scroll-wrapper" ref="scrollWrapper" :style="{ left: state.left + 'px' }">
      <slot></slot>
    </div>
    <span
      class="scrollBar scrollBar-right"
      v-show="state.scrollVisible"
      @click="scrollRight"
      :style="{
        //'border-left': '1px solid ' + theme.color,
        color: '#fff',
      }"
    >
      <el-icon style=""><ArrowRight /></el-icon>
    </span>
  </div>
</template>

<script setup>
  import { ref, reactive } from 'vue'
  defineOptions({ name: 'v-scroll-pane' })
  const padding = 15 // tag's padding
  const state = reactive({
    scrollVisible: false,
    left: 0,
  })
  const scrollContainer = ref(null)
  const scrollWrapper = ref(null)

  const handleScroll = function (e) {
    const eventDelta = e.wheelDelta || -e.deltaY * 3
    const $container = scrollContainer.value
    const $containerWidth = $container.offsetWidth
    const $wrapper = scrollWrapper.value
    const $wrapperWidth = $wrapper.offsetWidth

    if (eventDelta > 0) {
      state.left = Math.min(0, state.left + eventDelta)
    } else {
      if ($containerWidth - padding < $wrapperWidth) {
        if (state.left < -($wrapperWidth - $containerWidth + padding)) {
          state.left = state.left
        } else {
          state.left = Math.max(state.left + eventDelta, $containerWidth - $wrapperWidth - padding)
        }
      } else {
        state.left = 0
      }
    }
  }
  const hoverPane = function ($event) {
    const $container = scrollContainer.value
    const $containerWidth = $container.offsetWidth
    const $wrapper = scrollWrapper.value
    const $wrapperWidth = $wrapper.offsetWidth
    if ($containerWidth - padding < $wrapperWidth) {
      state.scrollVisible = true
    }
  }
  const leavePane = function ($event) {
    state.scrollVisible = false
  }
  const moveToTarget = function ($target) {
    const $container = scrollContainer.value
    const $containerWidth = $container.offsetWidth
    const $targetLeft = $target.offsetLeft
    const $targetWidth = $target.offsetWidth

    if ($targetLeft < -state.left) {
      // tag in the left
      state.left = -$targetLeft + padding
    } else if ($targetLeft + padding > -state.left && $targetLeft + $targetWidth < -state.left + $containerWidth - padding) {
      // tag in the current view
      // eslint-disable-line
    } else {
      // tag in the right
      state.left = -($targetLeft - ($containerWidth - $targetWidth) + padding)
    }
  }

  const scrollLeft = function () {
    const eventDelta = 300
    const $container = scrollContainer.value
    const $containerWidth = $container.offsetWidth
    const $wrapper = scrollWrapper.value
    const $wrapperWidth = $wrapper.offsetWidth

    if (eventDelta > 0) {
      state.left = Math.min(0, state.left + eventDelta)
    } else {
      if ($containerWidth - padding < $wrapperWidth) {
        if (state.left < -($wrapperWidth - $containerWidth + padding)) {
          state.left = state.left
        } else {
          state.left = Math.max(state.left + eventDelta, $containerWidth - $wrapperWidth - padding)
        }
      } else {
        state.left = 0
      }
    }
  }
  const scrollRight = function () {
    const eventDelta = -300
    const $container = scrollContainer.value
    const $containerWidth = $container.offsetWidth
    const $wrapper = scrollWrapper.value
    const $wrapperWidth = $wrapper.offsetWidth

    if (eventDelta > 0) {
      state.left = Math.min(0, state.left + eventDelta)
    } else {
      if ($containerWidth - padding < $wrapperWidth) {
        if (state.left < -($wrapperWidth - $containerWidth + padding)) {
          state.left = state.left
        } else {
          state.left = Math.max(state.left + eventDelta, $containerWidth - $wrapperWidth - padding)
        }
      } else {
        state.left = 0
      }
    }
  }

  //暴露方法
  defineExpose({
    moveToTarget,
    scrollLeft,
    scrollRight,
  })
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
  .scroll-container {
    white-space: nowrap;
    position: relative;
    overflow: hidden;
    width: 100%;
    .scroll-wrapper {
      position: absolute;
      display: flex;
      flex-direction: row;
      justify-content: flex-start;
      align-items: center;
      height: 100%;
    }
  }
  .scrollBar {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 8px;
    height: 34px;
    font-size: 14px;
    cursor: pointer;
    z-index: 100;
    background: transparent;
    background-color: rgba(0, 0, 0, 0.5);
    position: absolute;
  }
  .scrollBar-left {
    left: 0;
  }
  .scrollBar-right {
    right: 0;
  }
</style>
